﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using Hydra.Shell.Expressions;
using ExpressionSerialization;
using System.Collections.ObjectModel;
using System.Xml.Linq;
using System.Threading;
using System.ServiceModel.DomainServices.Client;
using HydraQueryProvider.QueryProviders;

namespace Hydra.Shell.QueryProviders
{
    public delegate void OnProcessExpressionHandler(XElement element, string path, out object result);

    public class HydraQueryProvider<T> : IQueryProvider
    {
        private ObservableCollection<T> collection;
        public event OnProcessExpressionHandler OnProcessExpression;

        public HydraQueryProvider(ObservableCollection<T> collection)
        {
            this.collection = new ObservableCollection<T>(collection);
        }

        public IQueryable<TElement> CreateQuery<TElement>(System.Linq.Expressions.Expression expression)
        {
            try
            {
                var expressionSerializer = new ExpressionSerializer();
                var element = expressionSerializer.Serialize(expression);

                var expressionString = expression.ToString();
                var visitor = new HydraVisitor(expression);

                if (visitor.BaseNode is MethodNode)
                {
                    MethodNode methodNode = (MethodNode)visitor.BaseNode;

                    switch (methodNode.Method.Name)
                    {
                        case "Cast":

                            var handlers = OnProcessExpression.GetInvocationList().Cast<OnProcessExpressionHandler>().ToArray();
                            return new HydraQueryable<TElement>(collection.AsQueryable().Cast<TElement>(), handlers);
                    }
                }
            }
            catch (Exception ex)
            {
                Debugger.Break();
            }

            return null;
        }

        public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
        {
            return this.CreateQuery<object>(expression);
        }

        public TResult Execute<TResult>(System.Linq.Expressions.Expression expression)
        {
            var expressionSerializer = new ExpressionSerializer();
            var element = expressionSerializer.Serialize(expression);
            var result = (object)null;

            OnProcessExpression(element, "", out result);

            return (TResult)result;
        }

        public object Execute(System.Linq.Expressions.Expression expression)
        {
            var visitor = new HydraVisitor(expression);

            throw new NotImplementedException();
        }
    }
}